package cn.com.klun.logic;

import cn.com.klun.tjy.base.ILogics;
import cn.com.klun.tjy.common.constant.ResultEnum;
import cn.com.klun.tjy.common.util.DateUtils;
import cn.com.klun.tjy.dao.entity.TblAllStockInfo;
import cn.com.klun.tjy.dao.entity.TblAveVolMacdInfo;
import cn.com.klun.tjy.dao.entity.TblStockDayInfos;
import cn.com.klun.tjy.dao.mapper.edit.TblAveVolMacdInfoEditMapper;
import cn.com.klun.tjy.dao.mapper.ser.TblAveVolMacdInfoSerMapper;
import cn.com.klun.tjy.dao.mapper.ser.TblStockDayInfosSerMapper;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * 计算AVE Vol MACD
 * 定时任务放在第二天执行
 */
@Service
public class CalculateAveVolMacdLogic implements ILogics<TblAllStockInfo> {

    private Logger logger = LoggerFactory.getLogger(CalculateAveVolMacdLogic.class);
    @Autowired
    private TblStockDayInfosSerMapper tblStockDayInfosSerMapper;
    @Autowired
    private TblAveVolMacdInfoSerMapper tblAveVolMacdInfoSerMapper;
    @Autowired
    private TblAveVolMacdInfoEditMapper tblAveVolMacdInfoEditMapper;

    @Override
    public ResultEnum exec(TblAllStockInfo tblAllStockInfo) throws Exception {

        boolean allFlag = true;
        long l = System.currentTimeMillis();
        int allCount = 0;
        while (allFlag) {
            allCount++;
            // 存储计算出来的信息
            TblAveVolMacdInfo tblAveVolMacdInfo = new TblAveVolMacdInfo();
            String stockCode = tblAllStockInfo.getEx() + tblAllStockInfo.getStockCode();
            String lastDay = "99999999";
            String today = "99999999";
            tblAveVolMacdInfo.setStoCode(stockCode);
            TblAveVolMacdInfo result = null;
            TblStockDayInfos tblStockDayInfos = null;
            // 添加计算多期逻辑
            boolean dayflag = true;
            int dayCount = 0;
            int rollCount = 0;
            while (dayflag) {
                if (Integer.parseInt(lastDay) < 20180212) {//20180212 最早一天的数据
                    return ResultEnum.OK;
                }
                if (null == result) {
                    // 对于循环次数过多的进行优化
                    rollCount++;
                    lastDay = DateUtils.addDay(DateUtils.getCurrDate(), --dayCount);
                    tblAveVolMacdInfo.setTrnDate(lastDay);
                    result = tblAveVolMacdInfoSerMapper.queryObj(tblAveVolMacdInfo);
                } else {
                    if (rollCount > 20) {
                        // 放入 redis 并且打印日志
                        Jedis jedis = new Jedis("39.107.115.53", 7777);
                        jedis.set("stockCode-" + stockCode, String.valueOf(rollCount));
                    }
                    today = DateUtils.addDay(DateUtils.getCurrDate(), ++dayCount);
                    ////如果日期大于今天 20 为可能出现的休市
                    if (Integer.parseInt(today) > Integer.parseInt(DateUtils.getCurrDate()) + 20) {
                        // 没有数据 当天的值不变 取上一天的懒得计算 可能股票不正规谨慎购买
                        // tblAveVolMacdInfoEditMapper.save(result);
                        return ResultEnum.OK;
                    } else {
                        tblStockDayInfos = new TblStockDayInfos();
                        tblStockDayInfos.setStoId(stockCode);
                        tblStockDayInfos.setTrnDate(today);
                        tblStockDayInfos = tblStockDayInfosSerMapper.queryObj(tblStockDayInfos);
                        if (null != tblStockDayInfos) {
                            dayflag = false;
                            logger.info("此次循环 tblStockDayInfos【{}】,交易日期：{}", tblAllStockInfo.getStockCode(), today);
                            logger.info("查询用时【{}】,dayCount=【{}】", String.valueOf(System.currentTimeMillis() - l), dayCount);
                        }
                    }
                }
            }

            // 40条数据-按照日期排序 (当天股价+前4个交 易日的收盘价)
            List<TblStockDayInfos> tblStockDayInfosList = tblStockDayInfosSerMapper.queryAveInfo(tblStockDayInfos);


            // 循环遍历 给数据赋值
            int listSize = tblStockDayInfosList.size();
            BigDecimal totalAmount = BigDecimal.ZERO;//平均值计算
            BigDecimal tempAmount = BigDecimal.ZERO;//作为中间值使用
            BigDecimal sumVOL = BigDecimal.ZERO;
            BigDecimal fuyi = new BigDecimal(-1);
            int count = 0; // 计算平均值 取值异常计数
            int volCount = 0;
            BigDecimal trueEndPri = BigDecimal.ZERO;
            List<BigDecimal> endPriList = new ArrayList<BigDecimal>();
            for (int i = 1; i <= listSize; i++) {
                tblStockDayInfos = tblStockDayInfosList.get(i - 1);

                // 当日的收盘价
                BigDecimal endPri = tblStockDayInfos.getEndPri();

                // 计算Vol的值 VOL=∑nVi/N 此处选择10的信息计算 Vi:i日成交量 N选定的时间参数 例如10或者30 此处选择10
                if (volCount < 10) {
                    BigDecimal trnNum = tblStockDayInfos.getTrnNum();//交易量
                    // 如果为-1不计算值
                    if (!fuyi.equals(trnNum)) {
                        sumVOL = sumVOL.add(trnNum).setScale(2, BigDecimal.ROUND_HALF_DOWN);
                        volCount++;
                    }
                    //计算正负值 如果当天的交易大于前一天的则为正，反之为负值
                    if (today.equals(tblStockDayInfos.getTrnDate()) && fuyi.equals(endPri)) {
                        tblAveVolMacdInfo.setVolFalg("0");
                    }
                    if (StringUtils.isEmpty(tblAveVolMacdInfo.getVolFalg())) {
                        if (!tempAmount.equals(BigDecimal.ZERO) && !fuyi.equals(tempAmount)) {
                            // 1:大于 -1：小于 0：等于或者无取值
                            tblAveVolMacdInfo.setVolFalg(tempAmount.compareTo(endPri) + "");
                        }
                    }
                }
                // tempAmount:存储上一次的endPri
                if (!fuyi.equals(endPri)) {
                    tempAmount = endPri;
                }
                tblAveVolMacdInfo.setVol(sumVOL.divide(new BigDecimal(volCount), 2, BigDecimal.ROUND_HALF_DOWN));
                // 计算MACD(12,26,9)
                //取前天的值 -初始值用sql填充
                if (today.equals(tblStockDayInfos.getTrnDate())) {
                    if (!fuyi.equals(endPri)) {
                        // EMA（12）= 前一日EMA（12）×11/13＋今日收盘价×2/13
                        // EMA（26）= 前一日EMA（26）×25/27＋今日收盘价×2/27
                        BigDecimal a = new BigDecimal(11).divide(new BigDecimal(13), 4, BigDecimal.ROUND_HALF_DOWN);
                        BigDecimal b = new BigDecimal(2).divide(new BigDecimal(13), 4, BigDecimal.ROUND_HALF_DOWN);
                        BigDecimal c = new BigDecimal(25).divide(new BigDecimal(27), 4, BigDecimal.ROUND_HALF_DOWN);
                        BigDecimal d = new BigDecimal(2).divide(new BigDecimal(27), 4, BigDecimal.ROUND_HALF_DOWN);
                        BigDecimal EMA12 = result.getEma12().multiply(a).add(endPri.multiply(b)).setScale(2, BigDecimal.ROUND_HALF_DOWN);
                        BigDecimal EMA26 = result.getEma26().multiply(c).add(endPri.multiply(d)).setScale(2, BigDecimal.ROUND_HALF_DOWN);
                        tblAveVolMacdInfo.setEma12(EMA12);
                        tblAveVolMacdInfo.setEma26(EMA26);
                        // 计算离差值（DIF） DIF=今日EMA（12）－今日EMA（26）
                        BigDecimal DIF = EMA12.subtract(EMA26);
                        tblAveVolMacdInfo.setDif(DIF);
                        // 今日DEA（MACD）=前一日DEA×8/10＋今日DIF×2/10
                        BigDecimal DEA = result.getDea().multiply(new BigDecimal(0.8)).add(DIF.multiply(new BigDecimal(0.2)));
                        tblAveVolMacdInfo.setDea(DEA);
                        // MACD=BAR=2×(DIF－DEA)
                        BigDecimal MACD = new BigDecimal(2).multiply(DIF.subtract(DEA)).setScale(2, BigDecimal.ROUND_HALF_DOWN);
                        tblAveVolMacdInfo.setMacd(MACD);
                    }
                } else {
                    // 取不到today的值 或者 值为-1 不变存取上一次的值
                    if (i == 1) { //取 i=1 是只赋值一次
                        tblAveVolMacdInfo.setEma12(result.getEma12());
                        tblAveVolMacdInfo.setEma26(result.getEma26());
                        tblAveVolMacdInfo.setDea(result.getDea());
                        tblAveVolMacdInfo.setMacd(result.getMacd());
                    }
                }

                // 计算平均值
                // 如果为-1 说明当天没有值，当天的收盘价取前一天的价格 对于停牌的没有做限制
                if (fuyi.equals(endPri) && i > count) {
                    boolean flag = true;
                    count = i;
                    while (flag) {
                        trueEndPri = tblStockDayInfosList.get((++count) - 1).getEndPri();
                        if (!fuyi.equals(endPri)) {
                            flag = false;
                        }
                    }
                }
                if (!fuyi.equals(endPri)) {
                    trueEndPri = endPri;
                }
                endPriList.add((i - 1), trueEndPri);
            }
            int endPriListSize = endPriList.size();
            BigDecimal M5 = BigDecimal.ZERO;
            BigDecimal M10 = BigDecimal.ZERO;
            BigDecimal M20 = BigDecimal.ZERO;
            BigDecimal M30 = BigDecimal.ZERO;
            for (int i = 0; i < endPriListSize; i++) {
                BigDecimal SingleEndPri = endPriList.get(i);
                totalAmount = totalAmount.add(SingleEndPri).setScale(2, BigDecimal.ROUND_HALF_DOWN);
                if (i == 4) {
                    M5 = totalAmount.divide(new BigDecimal(5), 2, BigDecimal.ROUND_HALF_DOWN);
                }
                if (i == 9) {
                    M10 = totalAmount.divide(new BigDecimal(10), 2, BigDecimal.ROUND_HALF_DOWN);
                }
                if (i == 19) {
                    M20 = totalAmount.divide(new BigDecimal(20), 2, BigDecimal.ROUND_HALF_DOWN);
                }
                if (i == 29) {
                    M30 = totalAmount.divide(new BigDecimal(30), 2, BigDecimal.ROUND_HALF_DOWN);
                    break;
                }
            }
            if (endPriListSize <= 29) {
                if (endPriListSize <= 19) {
                    if (endPriListSize <= 9) {
                        if (endPriListSize <= 4) {
                            M5 = totalAmount.divide(new BigDecimal(endPriListSize), 2, BigDecimal.ROUND_HALF_DOWN);
                        }
                        M10 = totalAmount.divide(new BigDecimal(endPriListSize), 2, BigDecimal.ROUND_HALF_DOWN);
                    }
                    M20 = totalAmount.divide(new BigDecimal(endPriListSize), 2, BigDecimal.ROUND_HALF_DOWN);
                }
                M30 = totalAmount.divide(new BigDecimal(endPriListSize), 2, BigDecimal.ROUND_HALF_DOWN);
            }
            // 赋值
            tblAveVolMacdInfo.setM5(M5);
            tblAveVolMacdInfo.setM10(M10);
            tblAveVolMacdInfo.setM20(M20);
            tblAveVolMacdInfo.setM30(M30);
            // 保存查询出来的值
            tblAveVolMacdInfo.setTrnDate(today);//把日期改为今天
            tblAveVolMacdInfoEditMapper.save(tblAveVolMacdInfo);
            // 总循环的结束条件 今天等于昨天的日期
            if (today.equals(DateUtils.addDay(DateUtils.getCurrDate(), -1))) {
                logger.info("保存成功，查询+计算用时：{}毫秒", String.valueOf(System.currentTimeMillis() - l));
                allFlag = false;
            }
            if (allCount > 90) {
                // 超过90天没有统计到数据 跳出循环 放入Redis中存储排查
                Jedis jedis = new Jedis("39.107.115.53", 7777);
                jedis.lpush("beyond90.stockId", tblAllStockInfo.getEx() + tblAllStockInfo.getStockCode());
            }
        }
        logger.info("任务完成用时：{}毫秒", String.valueOf(System.currentTimeMillis() - l));
        return ResultEnum.OK;
    }
}
